﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using MatrixControls;
using MatrixEditor.Properties;
using static MatrixEditor.DataFile;
using static MatrixEditor.Global;

namespace MatrixEditor
{
	public partial class FrmMain : Form
	{
		public readonly FrmPlayer PlayerForm = new FrmPlayer();
		public readonly FrmData DataForm     = new FrmData();

		private readonly List<Thumbnail> Thumbnails = new List<Thumbnail>(20);

		private readonly int thumbnail_padding = 4;
		private int current_thumbnail          = 0;
		private bool thumbnail_mouse_down      = false;

		private PixelBox[] Pixels;
#pragma warning disable IDE0044 // 添加只读修饰符
		private int canvas_row     = 6;
		private int canvas_column  = 9;
		private int canvas_padding = 4;
#pragma warning restore IDE0044 // 添加只读修饰符

		private ColorBox[] ColorBoxes;
		private readonly int colorbox_row     = 2;
		private readonly int colorbox_column  = 10;
		private readonly int colorbox_padding = 2;
		private readonly int colorbox_size    = 29;

		private readonly string default_ext = "matrix";
		private string output_filename      = null;

		private enum Directions
		{
			UP,
			DOWN,
			LEFT,
			RIGHT,
		};

		private enum Operations
		{
			ADD,    // 增加帧数据
			INSERT, // 在指定位置插入帧数据
			DELETE, // 删除指定帧数据
			RELOAD, // 重新加载缩略图
		};

		private enum FillColor
		{
			FORECOLOR,
			BACKCOLOR,
		}


		public FrmMain() => InitializeComponent();


		#region 自定义函数
		/// <summary>
		/// 初始化画布像素点
		/// </summary>
		private void InitializeCanvas()
		{
			PanelCanvas.Controls.Clear();

			Pixels = new PixelBox[canvas_column * canvas_row];

			int index;
			int pixel_width  = (PanelCanvas.Width - (canvas_column + 1) * canvas_padding) / canvas_column;
			int pixel_height = (PanelCanvas.Height - (canvas_row + 1) * canvas_padding) / canvas_row;
			int pixel_size   = Math.Min(pixel_width, pixel_height);

			for (int y = 0; y < canvas_column; y++)
			{
				for (int x = 0; x < canvas_row; x++)
				{
					index = y * canvas_row + x;

					Pixels[index] = new PixelBox
					{
						Name       = $"pixel_{index}",
						Index      = index,
						ColorIndex = 0,
						BoxColor   = Color.White,
						BoxSize    = pixel_size,
						Parent     = PanelCanvas,
						Location   = new Point(
							y * pixel_size + y * canvas_padding + canvas_padding,
							x * pixel_size + x * canvas_padding + canvas_padding
						),
					};
					Pixels[index].MouseDown += new MouseEventHandler(PixelClickEvnet);
				}
			}
		}

		/// <summary>
		/// 初始化色盘组件
		/// </summary>
		private void InitializeColorBox()
		{
			int index  = 0;
			ColorBoxes = new ColorBox[colorbox_column * colorbox_row];

			for (int y = 0; y < colorbox_column; y++)
			{
				for (int x = 0; x < colorbox_row; x++)
				{
					index = y * colorbox_row + x;

					ColorBoxes[index] = new ColorBox
					{
						Name     = $"colorbox_{y * colorbox_row + x}",
						Index    = index,
						BoxSize  = colorbox_size,
						Parent   = PanelProperties,
						TabStop  = false,
						BoxColor = Color.FromArgb(
							Colors[index, 0],
							Colors[index, 1],
							Colors[index, 2]
						),
						Location = new Point(
							(ColorBoxBackColor.Left + ColorBoxBackColor.Width + 16) +
							y * colorbox_size + y * colorbox_padding + colorbox_padding,
							x * colorbox_size + x * colorbox_padding + 6
						),
					};
					ColorBoxes[index].MouseDown += new MouseEventHandler(ColorBoxClickEvnet);
				}
			}
		}

		/// <summary>
		/// 初始化示例文件菜单
		/// </summary>
		private void InitializeSamplesMenu()
		{
			var res         = new Resources();
			var proper_info = res.GetType().GetProperties(
				BindingFlags.Static |
				BindingFlags.NonPublic |
				BindingFlags.Instance
			);

			foreach (var info in proper_info)
			{
				if (info.PropertyType.Name == "Byte[]")
				{
					var item = new ToolStripMenuItem()
					{
						Text = info.Name.ToUpper(),
						Name = info.Name,
					};
					item.Click += SampleItemClickEvent;

					MenuItemHelpSamples.DropDownItems.Add(item);
				}
			}
		}

		/// <summary>
		/// 启用控件双缓存处理
		/// </summary>
		/// <param name="control"></param>
		private void EnableDoubleBuffered(Control control)
		{
			control.GetType().GetProperty(
				"DoubleBuffered",
				BindingFlags.Instance | BindingFlags.NonPublic
			).SetValue(control, true, null);
		}

		/// <summary>
		/// 整体移动画布中的像素点
		/// </summary>
		/// <param name="direction">移动方向枚举常量</param>
		private void CanvasMove(Directions direction)
		{
			int current, next;

			switch (direction)
			{
				case Directions.UP:
					for (int y = 0; y < canvas_column; y++)
					{
						for (int x = 0; x < canvas_row - 1; x++)
						{
							current = y * canvas_row + x;
							next    = current + 1;

							if (Pixels[next].BoxColor != Pixels[current].BoxColor)
							{
								Pixels[current].ColorIndex = Pixels[next].ColorIndex;
								Pixels[current].BoxColor   = Pixels[next].BoxColor;
								Pixels[next].ColorIndex    = 0;
								Pixels[next].BoxColor      = Color.White;
							}
						}
					}

					break;
				case Directions.DOWN:
					for (int y = 0; y < canvas_column; y++)
					{
						for (int x = canvas_row - 1; x > 0; x--)
						{
							next    = y * canvas_row + x;
							current = next - 1;

							if (Pixels[next].BoxColor != Pixels[current].BoxColor)
							{
								Pixels[next].ColorIndex    = Pixels[current].ColorIndex;
								Pixels[next].BoxColor      = Pixels[current].BoxColor;
								Pixels[current].ColorIndex = 0;
								Pixels[current].BoxColor   = Color.White;
							}
						}
					}

					break;
				case Directions.LEFT:
					for (int y = 1; y < canvas_column; y++)
					{
						for (int x = 0; x < canvas_row; x++)
						{
							current = y * canvas_row + x;
							next    = current - canvas_row;

							if (Pixels[next].BoxColor != Pixels[current].BoxColor)
							{
								Pixels[next].ColorIndex    = Pixels[current].ColorIndex;
								Pixels[next].BoxColor      = Pixels[current].BoxColor;
								Pixels[current].ColorIndex = 0;
								Pixels[current].BoxColor   = Color.White;
							}
						}
					}

					break;
				case Directions.RIGHT:
					for (int y = canvas_column - 1; y > 0; y--)
					{
						for (int x = 0; x < canvas_row; x++)
						{
							next    = y * canvas_row + x;
							current = next - canvas_row;

							if (Pixels[next].BoxColor != Pixels[current].BoxColor)
							{
								Pixels[next].ColorIndex    = Pixels[current].ColorIndex;
								Pixels[next].BoxColor      = Pixels[current].BoxColor;
								Pixels[current].ColorIndex = 0;
								Pixels[current].BoxColor   = Color.White;
							}
						}
					}

					break;
				default:
					return;
			}

			for (int index = 0; index < canvas_row * canvas_column; index++)
			{
				Frames[current_thumbnail][index] = Pixels[index].ColorIndex;
			}

			Thumbnails[current_thumbnail].DrawPixels(Frames[current_thumbnail], Colors, SingleColor);

			FileChanged = true;
			UpdateFormTitle();
		}

		/// <summary>
		/// 响应像素格点击事件，更新像素格和帧画面内容
		/// </summary>
		/// <param name="pixel">当前点击的 PixelBox 对象</param>
		/// <param name="color">需要填充的颜色</param>
		private void UpdatePixelAndFrame(PixelBox pixel, FillColor color)
		{
			var colorbox    = color == FillColor.FORECOLOR ? ColorBoxForeColor : ColorBoxBackColor;
			int color_index = pixel.BoxColor != Color.White &&
							  pixel.BoxColor == colorbox.BoxColor ?
							  0 : colorbox.Index;

			pixel.ColorIndex = color_index;
			pixel.BoxColor   = SingleColor ? color_index == 0 ? Color.White : Color.Black : ColorBoxes[color_index].BoxColor;

			Frames[current_thumbnail][pixel.Index] = color_index;
			Thumbnails[current_thumbnail].DrawPixel(pixel.Index, pixel.BoxColor.ToArgb());

			FileChanged = true;
			UpdateFormTitle();
		}

		/// <summary>
		/// 对缩略图和帧数据集合进行增删改查等操作
		/// </summary>
		/// <param name="operate">操作枚举常量</param>
		private void ThumbnailOperates(Operations operate)
		{
			switch (operate)
			{
				case Operations.ADD:
				case Operations.INSERT:
					int[] default_array = Enumerable.Repeat(0, canvas_row * canvas_column).ToArray();
					var thumbnail       = new Thumbnail { Parent = PanelThumbnail };

					if (Operations.ADD == operate)
					{
						Frames.Add(default_array);
						Thumbnails.Add(thumbnail);
					}
					else
					{
						current_thumbnail++;
						Frames.Insert(current_thumbnail, default_array);
						Thumbnails.Insert(current_thumbnail, thumbnail);
					}

					thumbnail.MouseDown += new MouseEventHandler(ThumbnailMouseDownEvnet);
					thumbnail.MouseUp   += new MouseEventHandler(ThumbnailMouseUpEvent);
					thumbnail.MouseMove += new MouseEventHandler(ThumbnaiMouseMoveEvent);

					break;
				case Operations.DELETE:
					Frames.RemoveAt(current_thumbnail);
					Thumbnails.RemoveAt(current_thumbnail);
					PanelThumbnail.Controls.RemoveAt(current_thumbnail);

					current_thumbnail--;

					if (current_thumbnail < 0)
					{
						current_thumbnail = 0;

						if (Thumbnails.Count == 0) { ThumbnailOperates(Operations.ADD); }
					} else if (PanelThumbnail.Controls.Count > current_thumbnail + 1)
					{
						current_thumbnail++;
					}

					break;
				case Operations.RELOAD:
					// 调整和设置缩略图尺寸、索引号和选中状态
					for (int index = 0; index < Thumbnails.Count; index++)
					{
						Thumbnails[index].Name     = $"thumbnail_{index}";
						Thumbnails[index].BoxWidth = PanelThumbnail.ClientSize.Width - thumbnail_padding * 2;
						Thumbnails[index].Index    = index;
						Thumbnails[index].Selected = current_thumbnail == index;

						PanelThumbnail.Controls.SetChildIndex(Thumbnails[index], index);
					}

					PanelThumbnail.ScrollControlIntoView(Thumbnails[current_thumbnail]);

					break;
			}

			if (operate == Operations.ADD || operate == Operations.INSERT)
			{
				ThumbnailOperates(Operations.RELOAD);
			}

			if (operate == Operations.ADD || operate == Operations.INSERT || operate == Operations.DELETE)
			{
				FileChanged = true;
				UpdateFormTitle();
				SwitchThumbnail();
			}
		}

		/// <summary>
		/// 切换当前显示的缩略图和画布
		/// </summary>
		private void SwitchThumbnail()
		{
			ThumbnailOperates(Operations.RELOAD);
			Thumbnails[current_thumbnail].DrawPixels(Frames[current_thumbnail], Colors, SingleColor);

			Color color;

			for (int index = 0; index < canvas_row * canvas_column; index++)
			{
				if (SingleColor)
				{
					color = Frames[current_thumbnail][index] != 0 ? Color.Black : Color.White;
				}
				else
				{
					color = ColorBoxes[Frames[current_thumbnail][index]].BoxColor;
				}

				Pixels[index].ColorIndex = Frames[current_thumbnail][index];
				Pixels[index].BoxColor   = color;
			}
		}

		/// <summary>
		/// 重新加载缩略图控件并复位相关设置
		/// </summary>
		private void RefreshThumbnail()
		{
			PanelThumbnail.Controls.Clear();
			Thumbnails.Clear();

			for (int index = 0; index < Frames.Count; index++)
			{
				var thumbnail = new Thumbnail { Parent = PanelThumbnail };

				thumbnail.DrawPixels(Frames[index], Colors, SingleColor);

				thumbnail.MouseDown += new MouseEventHandler(ThumbnailMouseDownEvnet);
				thumbnail.MouseUp   += new MouseEventHandler(ThumbnailMouseUpEvent);
				thumbnail.MouseMove += new MouseEventHandler(ThumbnaiMouseMoveEvent);

				Thumbnails.Add(thumbnail);
			}

			current_thumbnail = 0;
			SwitchThumbnail();
			SwitchThumbnail();

			FileChanged    = false;
			output_filename = null;
			UpdateFormTitle();
		}

		/// <summary>
		/// 在窗体标题栏显示文件名和文件保存状态
		/// </summary>
		public void UpdateFormTitle()
		{
			string filename = string.IsNullOrEmpty(output_filename) ? "Untitled" : output_filename.Substring(output_filename.LastIndexOf("\\") + 1);

			Text = $"{Application.ProductName} - {filename} {(FileChanged ? "*" : string.Empty)}";

			PlayerForm.RefreshThumbnail();
		}

		/// <summary>
		/// 重置所有设置
		/// </summary>
		private void ResetSettings()
		{
			Frames.Clear();
			Thumbnails.Clear();
			PanelThumbnail.Controls.Clear();
			ResetColors();

			int index = 0;

			foreach (var colorbox in ColorBoxes)
			{
				colorbox.BoxColor = Color.FromArgb(
					Colors[index, 0],
					Colors[index, 1],
					Colors[index, 2]
				);

				index++;
			}

			current_thumbnail = 0;

			ColorBoxForeColor.Index = ColorBoxes[1].Index;
			ColorBoxForeColor.BoxColor = ColorBoxes[1].BoxColor;
			ColorBoxBackColor.Index = ColorBoxes[0].Index;
			ColorBoxBackColor.BoxColor = ColorBoxes[0].BoxColor;

			ThumbnailOperates(Operations.ADD);
			PanelThumbnail.PerformLayout();

			FileChanged = false;
			output_filename = null;

			UpdateFormTitle();
			DataForm.GeneratePythonCode();
		}
		
		/// <summary>
		/// 弹出对话框由用户决定是否丢弃当前已修改的内容
		/// </summary>
		/// <returns></returns>
		private bool PromptDroppingFile()
		{
			bool result;

			if (FileChanged)
			{
				var dialog_result = MessageBox.Show(
					"未保存的文件将被丢弃，是否继续？",
					Application.ProductName,
					MessageBoxButtons.YesNo,
					MessageBoxIcon.Question,
					MessageBoxDefaultButton.Button2
				);

				result = dialog_result == DialogResult.Yes;
			}
			else { result = true; }

			return result;
		}

		/// <summary>
		/// 从本地磁盘读取并导入指定文件
		/// </summary>
		/// <param name="filename">matrix 数据文件</param>
		/// <returns></returns>
		private bool LoadInputFile(string filename)
		{
			bool result = false;

			output_filename = filename;

			var error = Import(output_filename);

			switch (error)
			{
				case DATAFILE_ERROR.SUCCESS:
					int index = 0;

					foreach (var colorbox in ColorBoxes)
					{
						colorbox.BoxColor = Color.FromArgb(
							Colors[index, 0],
							Colors[index, 1],
							Colors[index, 2]
						);

						index++;
					}

					PanelThumbnail.Controls.Clear();
					Thumbnails.Clear();

					for (index = 0; index < Frames.Count; index++)
					{
						var thumbnail = new Thumbnail { Parent = PanelThumbnail };

						thumbnail.DrawPixels(Frames[index], Colors, SingleColor);

						thumbnail.MouseDown += new MouseEventHandler(ThumbnailMouseDownEvnet);
						thumbnail.MouseUp   += new MouseEventHandler(ThumbnailMouseUpEvent);
						thumbnail.MouseMove += new MouseEventHandler(ThumbnaiMouseMoveEvent);

						Thumbnails.Add(thumbnail);
					}

					current_thumbnail = 0;
					SwitchThumbnail();

					PlayerForm.UpdateControlsStatus();

					MenuItemSingleColor.Checked      = SingleColor;
					Settings.Default.MainSingleColor = SingleColor;
					Settings.Default.Save();

					result = true;

					break;
				case DATAFILE_ERROR.INVALID_FILE:
					MessageBox.Show("非法文件！", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
					break;
				case DATAFILE_ERROR.INVALID_DATA:
					MessageBox.Show("数据解码失败！", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
					break;
			}

			return result;
		}

		/// <summary>
		/// 打开并导入拖动到窗体上的数据文件
		/// </summary>
		/// <param name="filenames">拖动到窗体上的文件名列表</param>
		private void LoadingDroppedFile(Array filenames)
		{
			string file = null;

			foreach (string filename in filenames)
			{
				if (File.Exists(filename))
				{
					if (Path.GetExtension(filename).ToLower().Equals($".{default_ext}"))
					{
						file = filename; break;
					}
				}
			}

			if (file is null) { return; }

			if (!PromptDroppingFile()) { return; }

			if (LoadInputFile(file))
			{
				FileChanged = false;
				UpdateFormTitle();
				DataForm.GeneratePythonCode();
			}
		}

		private bool LoadingInputFile()
		{
			bool result = false;

			using (var dialog = new OpenFileDialog())
			{
				dialog.DefaultExt       = default_ext;
				dialog.CheckFileExists  = true;
				dialog.CheckPathExists  = true;
				dialog.RestoreDirectory = true;
				dialog.Filter           = $"矩阵文件 (*.{default_ext})|*.{default_ext}|所有文件 (*.*)|*.*";

				var load_result = dialog.ShowDialog();

				if (load_result == DialogResult.OK)
				{
					result = LoadInputFile(dialog.FileName);
				}
			};

			return result;
		}

		private bool SavingOutputFile()
		{
			bool result = false;

			if (string.IsNullOrEmpty(output_filename))
			{
				using (var dialog = new SaveFileDialog())
				{
					dialog.DefaultExt       = default_ext;
					dialog.CheckFileExists  = false;
					dialog.CheckPathExists  = true;
					dialog.OverwritePrompt  = true;
					dialog.RestoreDirectory = true;
					dialog.Filter           = $"矩阵文件 (*.{default_ext})|*.{default_ext}|所有文件 (*.*)|*.*";

					var save_result = dialog.ShowDialog();

					if (save_result == DialogResult.OK)
					{
						output_filename = dialog.FileName;

						var error = Export(output_filename);

						if (error == DATAFILE_ERROR.SUCCESS) { result = true; }
					}
				};
			} else if (FileChanged) {
				var error = Export(output_filename);

				if (error == DATAFILE_ERROR.SUCCESS) { result = true; }
			}

			return result;
		}

		public void RemoteLoadThumbnail(List<string> frames_string)
		{
			if (PromptDroppingFile())
			{
				Frames.Clear();

				foreach (string frame in frames_string)
				{
					int[] pixels_array = new int[canvas_row * canvas_column];
					string new_frames  = Convert.ToString(Convert.ToInt64(frame, 16), 2).PadLeft(canvas_row * canvas_column, '0');
					char[] frame_chars = new_frames.ToCharArray();

					for (int index = 0; index < pixels_array.Length; index++)
					{
						pixels_array[index] = Convert.ToInt16(Convert.ToString(frame_chars[index]), 16); // '0' 转 0，'1' 转 1
					}

					Frames.Add(pixels_array);
				}

				RefreshThumbnail();
			}
		}

		public void CheckMainFormStatus()
		{
			if (!PlayerForm.Visible && !DataForm.Visible) { BringToFront(); }
		}
		#endregion


		#region 动态添加控件的响应事件
		private void PanelThumbnail_DragDrop(object sender, DragEventArgs e)
		{
			var drop_data = (Array)e.Data.GetData(DataFormats.FileDrop, true);

			if (drop_data is null)
			{
				var point   = PanelThumbnail.PointToClient(new Point(e.X, e.Y));
				var control = PanelThumbnail.GetChildAtPoint(point);

				if (control != null)
				{
					int index     = PanelThumbnail.Controls.GetChildIndex(control, false);
					var thumbnail = (Thumbnail)e.Data.GetData(typeof(Thumbnail));

					if (index == thumbnail.Index) { return; }

					// 使用元组交换数据，这很 Python
					(Frames[index], Frames[thumbnail.Index]) = (Frames[thumbnail.Index], Frames[index]);

					thumbnail.DrawPixels(Frames[thumbnail.Index], Colors, SingleColor);

					current_thumbnail = index;
					SwitchThumbnail();

					FileChanged = true;
					UpdateFormTitle();
				}
			}
			else { LoadingDroppedFile(drop_data); }
		}

		private void PanelThumbnail_DragEnter(object sender, DragEventArgs e)
		{
			e.Effect = DragDropEffects.All;
		}

		private void PanelThumbnail_MouseWheel(object sender, MouseEventArgs e)
		{
			//PanelThumbnail.SuspendLayout();

			//if (e.Delta < 0)
			//{
			//	var point   = new Point(PanelThumbnail.Width / 2, PanelThumbnail.Height - Thumbnails[0].Height);
			//	var control = PanelThumbnail.GetChildAtPoint(point);

			//	PanelThumbnail.VerticalScroll.Value = PanelThumbnail.VerticalScroll.Minimum;
			//	PanelThumbnail.ScrollControlIntoView(control);
			//	PanelThumbnail.VerticalScroll.Value += Thumbnails[0].Margin.Bottom;
			//}
			//else
			//{
			//	var point   = new Point(PanelThumbnail.Width / 2, Thumbnails[0].Height / 2);
			//	var control = PanelThumbnail.GetChildAtPoint(point);

			//	if (PanelThumbnail.VerticalScroll.Value == PanelThumbnail.VerticalScroll.Minimum)
			//	{
			//		return;
			//	}
			//	PanelThumbnail.VerticalScroll.Value = PanelThumbnail.VerticalScroll.Maximum;
			//	PanelThumbnail.ScrollControlIntoView(control);
			//	PanelThumbnail.VerticalScroll.Value -= Thumbnails[0].Margin.Top;
			//}

			//PanelThumbnail.PerformLayout();
		}

		private void ThumbnailMouseDownEvnet(object sender, MouseEventArgs e)
		{
			current_thumbnail = (sender as Thumbnail).Index;
			SwitchThumbnail();

			if (e.Button == MouseButtons.Left) { thumbnail_mouse_down = true; }
		}

		private void ThumbnailMouseUpEvent(object sender, MouseEventArgs e)
		{
			thumbnail_mouse_down = false;
		}

		private void ThumbnaiMouseMoveEvent(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left && thumbnail_mouse_down)
			{
				thumbnail_mouse_down = false;

				var thumbnail = (Thumbnail)sender;

				if (thumbnail == null) { return; }

				PanelThumbnail.DoDragDrop(thumbnail, DragDropEffects.Move);
			}
		}

		private void PixelClickEvnet(object sender, MouseEventArgs e)
		{
			var color = e.Button == MouseButtons.Right ? FillColor.BACKCOLOR : FillColor.FORECOLOR;

			UpdatePixelAndFrame(sender as PixelBox, color);
		}

		private void ColorBoxClickEvnet(object sender, MouseEventArgs e)
		{
			var colorbox = sender as ColorBox;

			if (e.Button == MouseButtons.Left)
			{
				ColorBoxForeColor.Index    = colorbox.Index;
				ColorBoxForeColor.BoxColor = colorbox.BoxColor;
			}
			else if (e.Button == MouseButtons.Right)
			{
				ColorBoxBackColor.Index    = colorbox.Index;
				ColorBoxBackColor.BoxColor = colorbox.BoxColor;
			}
		}

		private void SampleItemClickEvent(object sender, EventArgs e)
		{
			if (PromptDroppingFile())
			{
				BeginInvoke(new Action(() =>
				{
					byte[] data = (byte[])Resources.ResourceManager.GetObject(
						(sender as ToolStripMenuItem).Name,
						Resources.Culture
					);

					ImportFromResources(data);

					int index = 0;

					foreach (var colorbox in ColorBoxes)
					{
						colorbox.BoxColor = Color.FromArgb(
							Colors[index, 0],
							Colors[index, 1],
							Colors[index, 2]
						);

						index++;
					}

					RefreshThumbnail();

					PlayerForm.UpdateControlsStatus();

					MenuItemSingleColor.Checked      = SingleColor;
					Settings.Default.MainSingleColor = SingleColor;
					Settings.Default.Save();

					FileChanged = false;
					UpdateFormTitle();
					DataForm.GeneratePythonCode();
				}));
			}
		}
		#endregion


		#region 窗体控件事件
		private void ButtonMoveUp_Click(object sender, EventArgs e) => CanvasMove(Directions.UP);

		private void ButtonMoveDown_Click(object sender, EventArgs e) => CanvasMove(Directions.DOWN);

		private void ButtonMoveLeft_Click(object sender, EventArgs e) => CanvasMove(Directions.LEFT);

		private void ButtonMoveRight_Click(object sender, EventArgs e) => CanvasMove(Directions.RIGHT);

		private void FrmMain_Load(object sender, EventArgs e)
		{
			EnableDoubleBuffered(PanelThumbnail);
			EnableDoubleBuffered(PanelCanvas);
			EnableDoubleBuffered(PanelProperties);

			InitializeCanvas();
			InitializeColorBox();
			InitializeSamplesMenu();

			ResetSettings();

			AddOwnedForm(PlayerForm);
			AddOwnedForm(DataForm);

			SingleColor = Settings.Default.MainSingleColor;
			MenuItemSingleColor.Checked = SingleColor;

			PlayerForm.Location = new Point(Left + Width - 14, Top);
			PlayerForm.Visible  = Settings.Default.PlayerVisible;

			DataForm.Location = new Point(Left + Width - DataForm.Width, Top);

			PanelThumbnail.ContextMenuStrip = MenuStripThumbnail;

			PanelThumbnail.DragDrop   += new DragEventHandler(PanelThumbnail_DragDrop);
			PanelThumbnail.DragEnter  += new DragEventHandler(PanelThumbnail_DragEnter);
			// PanelThumbnail.MouseWheel += new MouseEventHandler(PanelThumbnail_MouseWheel);


			// 以文件关联方式打开程序并导入数据文件
			string[] param = Environment.GetCommandLineArgs();
			
			if (param.Length > 1) { LoadingDroppedFile(param.Skip(1).ToArray()); }
		}

		private void FrmMain_Move(object sender, EventArgs e)
		{
			PlayerForm.Location = new Point(Left + Width - 14, Top);
			DataForm.Location   = new Point(Left + Width - DataForm.Width, Top);
		}

		private void FrmMain_KeyUp(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case Keys.Up:
					CanvasMove(Directions.UP);
					break;
				case Keys.Down:
					CanvasMove(Directions.DOWN);
					break;
				case Keys.Left:
					CanvasMove(Directions.LEFT);
					break;
				case Keys.Right:
					CanvasMove(Directions.RIGHT);
					break;
				case Keys.Enter:
				case Keys.Space:
					if (PlayerForm.Visible) { PlayerForm.PlayFrames(); }
					break;
				case Keys.A:
					PlayerForm.ShowFrame(false);
					break;
				case Keys.D:
					PlayerForm.ShowFrame();
					break;
				case Keys.W:
					PlayerForm.ChagnePeroidValue(true);
					break;
				case Keys.S:
					PlayerForm.ChagnePeroidValue(false);
					break;
			}
		}

		private void FrmMain_DragEnter(object sender, DragEventArgs e)
		{
			e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.All : DragDropEffects.None;
		}

		private void FrmMain_DragDrop(object sender, DragEventArgs e)
		{
			LoadingDroppedFile((Array)e.Data.GetData(DataFormats.FileDrop, true));
		}

		private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (FileChanged)
			{
				var result = MessageBox.Show(
					"文件已修改，是否保存？",
					Application.ProductName,
					MessageBoxButtons.YesNoCancel,
					MessageBoxIcon.Question,
					MessageBoxDefaultButton.Button3
				);

				if (result == DialogResult.Yes)
				{
					if (!SavingOutputFile()) { e.Cancel = true; }
				}
				else if (result == DialogResult.Cancel) { e.Cancel = true; }
			}
		}
		#endregion


		#region 菜单控件事件
		private void MenuItemThumbnailNew_Click(object sender, EventArgs e) => ThumbnailOperates(Operations.INSERT);

		private void MenuItemThumbnailDuplicate_Click(object sender, EventArgs e)
		{
			ThumbnailOperates(Operations.INSERT);

			int[] duplicate = new int[canvas_row * canvas_column];

			Array.Copy(Frames[current_thumbnail - 1], duplicate, duplicate.Length);
			Frames[current_thumbnail] = duplicate;

			SwitchThumbnail();
		}

		private void MenuItemThumbnailDelete_Click(object sender, EventArgs e) => ThumbnailOperates(Operations.DELETE);

		private void MenuItemFileNew_Click(object sender, EventArgs e)
		{
			if (FileChanged)
			{
				var result = MessageBox.Show(
					"文件已修改，是否保存？",
					Application.ProductName,
					MessageBoxButtons.YesNoCancel,
					MessageBoxIcon.Question,
					MessageBoxDefaultButton.Button3
				);

				if (result == DialogResult.Yes)
				{
					if (SavingOutputFile()) { ResetSettings(); }
				}
				else if (result == DialogResult.No) { ResetSettings(); }
			} else { ResetSettings(); }
		}

		private void MenuItemFileOpen_Click(object sender, EventArgs e)
		{
			bool file_loaded = false;

			if (FileChanged)
			{
				var result = MessageBox.Show(
					"文件已修改，是否保存？",
					Application.ProductName,
					MessageBoxButtons.YesNoCancel,
					MessageBoxIcon.Question,
					MessageBoxDefaultButton.Button3
				);

				if (result == DialogResult.Yes)
				{
					if (SavingOutputFile()) { file_loaded = LoadingInputFile(); }
				}
				else if (result == DialogResult.No) { file_loaded = LoadingInputFile(); }
			} else { file_loaded = LoadingInputFile(); }

			if (file_loaded)
			{
				FileChanged = false;
				UpdateFormTitle();
				DataForm.GeneratePythonCode();
			}
		}

		private void MenuItemSave_Click(object sender, EventArgs e)
		{
			if (SavingOutputFile())
			{
				FileChanged = false;
				UpdateFormTitle();
			}
		}

		private void MenuItemSaveAs_Click(object sender, EventArgs e)
		{
			string temp_filename = output_filename;
			output_filename = null;

			if (SavingOutputFile())
			{
				FileChanged = false;
				UpdateFormTitle();
			} else {
				output_filename = temp_filename;
			}
		}

		private void MenuItemFileExit_Click(object sender, EventArgs e) => Application.Exit();

		public void MenuItemViewPlayer_Click(object sender, EventArgs e)
		{
			PlayerForm.Visible = !PlayerForm.Visible;
		}

		public void MenuItemViewData_Click(object sender, EventArgs e)
		{
			//DataForm.Visible = !DataForm.Visible;
		}

		private void MenuItemSingleColor_Click(object sender, EventArgs e)
		{
			SingleColor = !SingleColor;
			MenuItemSingleColor.Checked = SingleColor;

			Settings.Default.MainSingleColor = SingleColor;
			Settings.Default.Save();

			RefreshThumbnail();
			SwitchThumbnail();
		}

		private void MenuItemHelpAbout_Click(object sender, EventArgs e)
		{
			var AboutForm = new FrmAbout();

			AboutForm.ShowDialog();
			AboutForm.Dispose();
		}
		#endregion
	}
}
